<template>
  <div class="app-container">
    <div class="app-container_title">{{ useTitle() }}</div>
    <el-form
      :model="queryParams"
      ref="queryRef"
      v-show="showSearch"
      :inline="true"
      label-width="68px"
    >
      <el-form-item label="项目名称" prop="project">
        <el-input
          v-model="queryParams.project"
          placeholder="请输入项目名称"
          clearable
          style="width: 240px"
          @keyup.enter="handleQuery"
        />
      </el-form-item>
      <el-form-item label="算法名称" prop="name">
        <el-input
          v-model="queryParams.name"
          placeholder="请输入算法名称"
          clearable
          style="width: 240px"
          @keyup.enter="handleQuery"
        />
      </el-form-item>
      <el-form-item label="任务场景" prop="scenario">
        <el-select
          v-model="queryParams.scenario"
          placeholder="任务场景"
          clearable
          style="width: 240px"
        >
          <el-option label="预测性维护" value="预测性维护" />
          <el-option label="物体识别" value="物体识别" />
          <el-option label="情感分析" value="情感分析" />
          <el-option label="语音识别" value="语音识别" />
        </el-select>
      </el-form-item>
      <el-form-item label="算法框架" prop="framework">
        <el-select
          v-model="queryParams.framework"
          placeholder="算法框架"
          clearable
          style="width: 240px"
        >
          <el-option
            v-for="framework in frameworkOptions"
            :key="framework"
            :label="framework"
            :value="framework"
          />
        </el-select>
      </el-form-item>
      <el-form-item>
        <el-button @click="handleQuery">查询</el-button>
        <el-button @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>
    <el-row :gutter="10" class="mb8">
      <el-col :span="1.5">
        <el-button type="primary" icon="Plus" @click="handleAdd"
          >新建算法</el-button
        >
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="danger"
          icon="Delete"
          :disabled="multiple"
          @click="handleBatchDelete"
          >批量删除</el-button
        >
      </el-col>
      <!-- <right-toolbar v-model:showSearch="showSearch"></right-toolbar> -->
      <!-- @queryTable="getList" -->
    </el-row>

    <!-- 表格数据 -->
    <div class="table-wrapper">
      <div class="table-wrapper_main">
        <el-table
          v-loading="loading"
          :data="algorithmList"
          @selection-change="handleSelectionChange"
          @row-click="handleRowClick"
        >
          <el-table-column type="selection" width="55" align="center" />
          <el-table-column label="算法名称" prop="name" width="120" />
          <el-table-column
            label="项目名称"
            prop="project"
            :show-overflow-tooltip="true"
            width="150"
          />
          <el-table-column
            label="算法描述"
            prop="description"
            :show-overflow-tooltip="true"
            width="150"
          />
          <el-table-column label="任务场景" prop="scenario" />
          <el-table-column label="算法框架" prop="framework" />
          <el-table-column label="算法版本" prop="version" />
          <el-table-column label="Python版本" prop="python_version" />
          <el-table-column label="创建时间" align="center" prop="created_at">
            <template #default="scope">
              <span>{{ scope.row.created_at }}</span>
            </template>
          </el-table-column>
          <el-table-column
            label="操作"
            align="center"
            class-name="small-padding fixed-width"
          >
            <template #default="scope">
              <el-tooltip content="修改" placement="top">
                <el-button
                  link
                  type="primary"
                  icon="Edit"
                  @click.stop="handleUpdate(scope.row)"
                ></el-button>
              </el-tooltip>
              <el-tooltip content="删除" placement="top">
                <el-button
                  link
                  type="danger"
                  icon="Delete"
                  @click.stop="handleDelete(scope.row)"
                ></el-button>
              </el-tooltip>
              <el-tooltip content="下载代码" placement="top">
                <el-button
                  link
                  type="primary"
                  icon="Download"
                  @click.stop="handleDownload(scope.row)"
                ></el-button>
              </el-tooltip>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <pagination
        v-show="total > 0"
        :total="total"
        :current-page="queryParams.pageNum"
        :page-size="queryParams.pageSize"
        @update:current-page="queryParams.pageNum = $event"
        @update:page-size="queryParams.pageSize = $event"
        @pagination="getList"
      />
    </div>

    <el-dialog :title="title" v-model="open" width="800px" append-to-body>
      <el-form
        ref="algorithmForm"
        :model="form"
        :rules="rules"
        label-width="120px"
      >
        <!-- 基本信息配置 -->
        <div class="form-section">
          <h3 class="section-title">基本信息配置</h3>
          <!-- 上传算法包 -->
          <el-form-item
            label="上传算法包"
            prop="algorithmFile"
            :rules="fileRules"
          >
            <el-upload
              class="upload-demo"
              drag
              action="#"
              :on-change="handleFileChange"
              :before-upload="beforeUpload"
              :file-list="form.algorithmFileList"
              :on-remove="handleRemoveFile"
              accept=".zip,.tar,.tar.gz,.tar.bz2,.tar.xz"
            >
              <i class="el-icon-upload"></i>
              <div class="el-upload__text">拖拽文件或点击上传</div>
            </el-upload>
          </el-form-item>

          <!-- 项目名称 -->
          <el-form-item label="项目名称" prop="project">
            <el-input v-model="form.project" placeholder="请输入项目名称" />
          </el-form-item>

          <!-- 算法名称 -->
          <el-form-item label="算法名称" prop="name">
            <el-input v-model="form.name" placeholder="请输入算法名称" />
          </el-form-item>

          <!-- 算法场景 -->
          <el-form-item label="算法场景" prop="scenario">
            <el-select v-model="form.scenario" placeholder="请选择算法场景">
              <el-option label="预测性维护" value="预测性维护"></el-option>
              <el-option label="物体识别" value="物体识别"></el-option>
              <el-option label="情感分析" value="情感分析"></el-option>
              <el-option label="语音识别" value="语音识别"></el-option>
              <el-option label="人脸识别" value="人脸识别"></el-option>
            </el-select>
          </el-form-item>

          <!-- 入口类名 -->
          <el-form-item label="入口类名" prop="entry_class">
            <el-input v-model="form.entry_class" placeholder="请输入入口类名" />
          </el-form-item>

          <!-- 算法框架 -->
          <el-form-item label="算法框架" prop="framework">
            <el-select v-model="form.framework" placeholder="请选择算法框架">
              <el-option
                v-for="framework in frameworkOptions"
                :key="framework"
                :label="framework"
                :value="framework"
              />
            </el-select>
          </el-form-item>

          <!-- 算法版本 -->
          <el-form-item label="算法版本" prop="version">
            <el-input v-model="form.version" placeholder="请输入算法版本" />
          </el-form-item>

          <!-- Python版本 -->
          <el-form-item label="Python版本" prop="python_version">
            <el-input
              v-model="form.python_version"
              placeholder="请输入Python版本"
            />
          </el-form-item>

          <!-- 算法描述 -->
          <el-form-item label="算法描述" prop="description">
            <el-input
              v-model="form.description"
              type="textarea"
              placeholder="请输入算法描述"
            />
          </el-form-item>
        </div>

        <!-- 数据中台接口配置 -->
        <div class="form-section">
          <h3 class="section-title">数据中台接口配置</h3>

          <!-- 测试环境 -->
          <div class="env-section">
            <h4 class="env-title">测试环境</h4>
            <el-form-item label="API方法" prop="testApiMethod">
              <el-select
                v-model="form.testApiMethod"
                placeholder="请选择API方法"
                style="width: 100%"
              >
                <el-option label="GET" value="GET" />
                <el-option label="POST" value="POST" />
                <el-option label="PUT" value="PUT" />
                <el-option label="DELETE" value="DELETE" />
              </el-select>
            </el-form-item>
            <el-form-item label="API Host" prop="testApiHost">
              <el-input
                v-model="form.testApiHost"
                placeholder="请输入API Host"
              />
            </el-form-item>
            <el-form-item label="API路径" prop="testApiDataPath">
              <el-input
                v-model="form.testApiDataPath"
                placeholder="请输入API路径"
              />
            </el-form-item>
            <el-form-item label="请求类" prop="testDataRequestClass">
              <el-input
                v-model="form.testDataRequestClass"
                placeholder="请输入请求类"
              />
            </el-form-item>
            <el-form-item label="响应类" prop="testDataResponseClass">
              <el-input
                v-model="form.testDataResponseClass"
                placeholder="请输入响应类"
              />
            </el-form-item>
          </div>

          <!-- 生产环境 -->
          <div class="env-section">
            <h4 class="env-title">生产环境</h4>
            <el-form-item label="API方法" prop="prodApiMethod">
              <el-select
                v-model="form.prodApiMethod"
                placeholder="请选择API方法"
                style="width: 100%"
              >
                <el-option label="GET" value="GET" />
                <el-option label="POST" value="POST" />
                <el-option label="PUT" value="PUT" />
                <el-option label="DELETE" value="DELETE" />
              </el-select>
            </el-form-item>
            <el-form-item label="API Host" prop="prodApiHost">
              <el-input
                v-model="form.prodApiHost"
                placeholder="请输入API Host"
              />
            </el-form-item>
            <el-form-item label="API路径" prop="prodApiDataPath">
              <el-input
                v-model="form.prodApiDataPath"
                placeholder="请输入API路径"
              />
            </el-form-item>
            <el-form-item label="请求类" prop="prodDataRequestClass">
              <el-input
                v-model="form.prodDataRequestClass"
                placeholder="请输入请求类"
              />
            </el-form-item>
            <el-form-item label="响应类" prop="prodDataResponseClass">
              <el-input
                v-model="form.prodDataResponseClass"
                placeholder="请输入响应类"
              />
            </el-form-item>
          </div>
        </div>
      </el-form>

      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">确 定</el-button>
          <el-button @click="cancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup name="Algorithm">
import { ref, reactive, toRefs, getCurrentInstance, onMounted } from "vue";
import { useRouter } from "vue-router";
import { useTitle } from "@/utils/dynamicTitle";
import { ElMessage, ElMessageBox } from "element-plus";
import {
  listAlgorithms,
  searchAlgorithms,
  getAlgorithmFrameworks,
  uploadAlgorithmPackage,
  saveAlgorithmConfig,
  getAlgorithm,
  updateAlgorithm,
  delAlgorithm,
  delAlgorithmBatch,
  downloadAlgorithm,
} from "@/api/algorithm";

const router = useRouter();
const { proxy } = getCurrentInstance();

const getInitialFormState = () => ({
  file_id: "",
  project: "",
  name: "",
  scenario: "",
  entry_class: "",
  framework: "",
  version: "",
  python_version: "",
  description: "",
  algorithmFile: null,
  algorithmFileList: [],

  testApiMethod: "",
  testApiHost: "",
  testApiDataPath: "",
  testDataRequestClass: "",
  testDataResponseClass: "",

  prodApiMethod: "",
  prodApiHost: "",
  prodApiDataPath: "",
  prodDataRequestClass: "",
  prodDataResponseClass: "",
});

const algorithmList = ref([]);
const frameworkOptions = ref([]);
const open = ref(false);
const total = ref(0);

const loading = ref(false);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);

const title = ref("");

const data = reactive({
  form: getInitialFormState(),
  queryParams: {
    pageNum: 1,
    pageSize: 10,
    project: undefined,
    name: undefined,
    scenario: undefined,
    framework: undefined,
  },
  rules: {
    project: [{ required: true, message: "请输入项目名称", trigger: "blur" }],
    name: [{ required: true, message: "请输入算法名称", trigger: "blur" }],
    scenario: [
      { required: true, message: "请选择算法场景", trigger: "change" },
    ],
    entry_class: [
      { required: true, message: "请输入入口类名", trigger: "blur" },
    ],
    framework: [
      { required: true, message: "请选择算法框架", trigger: "change" },
    ],
    version: [{ required: true, message: "请输入算法版本", trigger: "blur" }],
    python_version: [
      { required: true, message: "请输入Python版本", trigger: "blur" },
    ],
    description: [
      { required: true, message: "请输入算法描述", trigger: "blur" },
    ],
  },
  fileRules: [{ required: true, message: "请上传算法文件", trigger: "change" }],
});

const { queryParams, form, rules } = toRefs(data);

/** 查询算法列表 */
function getList() {
  loading.value = true;

  // 如果有搜索条件，使用搜索接口
  const hasSearchParams =
    queryParams.value.project ||
    queryParams.value.name ||
    queryParams.value.scenario ||
    queryParams.value.framework;

  if (hasSearchParams) {
    // 过滤空值
    const searchQuery = Object.fromEntries(
      Object.entries(queryParams.value).filter(
        ([key, value]) => value !== undefined && value !== ""
      )
    );

    searchAlgorithms(searchQuery)
      .then((response) => {
        algorithmList.value = response || [];
        total.value = algorithmList.value.length;
        loading.value = false;
      })
      .catch(() => {
        loading.value = false;
      });
  } else {
    listAlgorithms()
      .then((response) => {
        algorithmList.value = response.items || [];
        total.value = response.pagination.total || 0;
        loading.value = false;
      })
      .catch(() => {
        loading.value = false;
      });
  }
}

/** 搜索按钮操作 */
function handleQuery() {
  queryParams.value.pageNum = 1;
  getList();
}

/** 重置按钮操作 */
function resetQuery() {
  proxy.resetForm("queryRef");
  handleQuery();
}

/** 删除按钮操作 */
function handleDelete(row) {
  const algorithmId = row.file_id;
  ElMessageBox.confirm('是否确认删除算法"' + row.name + '"?', "警告", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(() => {
    delAlgorithm(algorithmId)
      .then(() => {
        getList();
        ElMessage.success("删除成功");
      })
      .catch(() => {
        ElMessage.error("删除失败");
      });
  });
}

/** 多选框选中数据 */
function handleSelectionChange(selection) {
  ids.value = selection.map((item) => item.file_id);
  single.value = selection.length != 1;
  multiple.value = !selection.length;
}

/** 重置新增的表单以及其他数据  */
function reset() {
  form.value = getInitialFormState();
  proxy.$nextTick(() => {
    if (proxy.$refs["algorithmForm"]) {
      proxy.$refs["algorithmForm"].clearValidate();
    }
  });
}

/** 添加角色 */
function handleAdd() {
  reset();
  open.value = true;
  title.value = "新建算法";
}

/** 修改算法 */
function handleUpdate(row) {
  reset();
  open.value = true;
  title.value = "编辑算法";

  // 获取完整的算法详情数据
  getAlgorithm(row.file_id)
    .then((response) => {
      // 填充算法基本信息
      if (response && response.algo_info) {
        const algoInfo = response.algo_info;
        form.value.file_id = algoInfo.file_id || row.file_id;
        form.value.project = algoInfo.project || "";
        form.value.name = algoInfo.name || "";
        form.value.scenario = algoInfo.scenario || "";
        form.value.entry_class = algoInfo.entry_class || "";
        form.value.framework = algoInfo.framework || "";
        form.value.version = algoInfo.version || "";
        form.value.python_version = algoInfo.python_version || "";
        form.value.description = algoInfo.description || "";
      } else {
        // 如果API返回格式不同，使用表格行数据
        form.value = { ...row };
      }

      // 填充测试环境配置
      if (response && response.dev_env && response.dev_env.testing_env) {
        const testEnv = response.dev_env.testing_env;
        form.value.testApiMethod = testEnv.api_method || "";
        form.value.testApiHost = testEnv.api_host || "";
        form.value.testApiDataPath = testEnv.api_path || "";
        form.value.testDataRequestClass = testEnv.request_class || "";
        form.value.testDataResponseClass = testEnv.response_class || "";
      }

      // 填充生产环境配置
      if (response && response.dev_env && response.dev_env.production_env) {
        const prodEnv = response.dev_env.production_env;
        form.value.prodApiMethod = prodEnv.api_method || "";
        form.value.prodApiHost = prodEnv.api_host || "";
        form.value.prodApiDataPath = prodEnv.api_path || "";
        form.value.prodDataRequestClass = prodEnv.request_class || "";
        form.value.prodDataResponseClass = prodEnv.response_class || "";
      }
    })
    .catch(() => {
      // 如果获取详情失败，使用表格行数据作为回退
      form.value = { ...row };
      ElMessage.warning("获取算法详情失败，部分字段可能无法回显");
    });
}
/** 提交按钮 */
function submitForm() {
  proxy.$refs["algorithmForm"].validate((valid) => {
    if (valid) {
      if (title.value === "编辑算法") {
        // 编辑模式
        updateAlgorithm(form.value.file_id, {
          algo_info: {
            file_id: form.value.file_id,
            project: form.value.project,
            name: form.value.name,
            scenario: form.value.scenario,
            entry_class: form.value.entry_class,
            framework: form.value.framework,
            version: form.value.version,
            python_version: form.value.python_version,
            description: form.value.description,
          },
          dev_env: {
            testing_env: {
              api_method: form.value.testApiMethod,
              api_host: form.value.testApiHost,
              api_path: form.value.testApiDataPath,
              api_headers: {
                "Content-Type": "application/json",
              },
              api_params: {
                dataset: "test_data",
              },
              request_class: form.value.testDataRequestClass,
              response_class: form.value.testDataResponseClass,
            },
            production_env: {
              api_method: form.value.prodApiMethod,
              api_host: form.value.prodApiHost,
              api_path: form.value.prodApiDataPath,
              api_headers: {
                "Content-Type": "application/json",
              },
              api_params: {
                dataset: "test_data",
              },
              request_class: form.value.prodDataRequestClass,
              response_class: form.value.prodDataResponseClass,
            },
          },
        })
          .then(() => {
            ElMessage.success("修改成功");
            open.value = false;
            getList();
          })
          .catch(() => {
            ElMessage.error("修改失败");
          });
      } else {
        // 新增模式
        saveAlgorithmConfig({
          algo_info: {
            file_id: form.value.file_id,
            project: form.value.project,
            name: form.value.name,
            scenario: form.value.scenario,
            entry_class: form.value.entry_class,
            framework: form.value.framework,
            version: form.value.version,
            python_version: form.value.python_version,
            description: form.value.description,
          },
          dev_env: {
            testing_env: {
              api_method: form.value.testApiMethod,
              api_host: form.value.testApiHost,
              api_path: form.value.testApiDataPath,
              api_headers: {
                "Content-Type": "application/json",
              },
              api_params: {
                dataset: "test_data",
              },
              request_class: form.value.testDataRequestClass,
              response_class: form.value.testDataResponseClass,
            },
            production_env: {
              api_method: form.value.prodApiMethod,
              api_host: form.value.prodApiHost,
              api_path: form.value.prodApiDataPath,
              api_headers: {
                "Content-Type": "application/json",
              },
              api_params: {
                dataset: "test_data",
              },
              request_class: form.value.prodDataRequestClass,
              response_class: form.value.prodDataResponseClass,
            },
          },
        })
          .then(() => {
            ElMessage.success("新增成功");
            open.value = false;
            getList();
          })
          .catch(() => {
            ElMessage.error("新增失败");
          });
      }
    }
  });
}

/** 取消按钮 */
function cancel() {
  open.value = false;
  reset();
}

/**点击某一行 */
function handleRowClick(row) {
  // router.push(`/algorithm/details/${row.file_id}`);
}

/** 下载代码操作 */
function handleDownload(row) {
  ElMessageBox.confirm('是否确认下载算法"' + row.name + '"的代码?', "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "info",
  }).then(() => {
    downloadAlgorithm(row.file_id)
      .then((blob) => {
        // 创建下载链接
        const url = window.URL.createObjectURL(blob);
        const link = document.createElement("a");
        link.href = url;
        link.download = `${row.name}_${row.version}.zip`;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        window.URL.revokeObjectURL(url);
        ElMessage.success("下载成功");
      })
      .catch(() => {
        ElMessage.error("下载失败");
      });
  });
}

/** 批量删除按钮操作 */
function handleBatchDelete() {
  if (ids.value.length === 0) {
    ElMessage.warning("请选择要删除的算法");
    return;
  }
  ElMessageBox.confirm(
    "是否确认删除选中的" + ids.value.length + "条数据项?",
    "警告",
    {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    }
  ).then(() => {
    delAlgorithmBatch(ids.value)
      .then(() => {
        getList();
        ElMessage.success("删除成功");
      })
      .catch(() => {
        ElMessage.error("删除失败");
      });
  });
}

/** 获取算法框架列表 */
function getFrameworkList() {
  getAlgorithmFrameworks()
    .then((response) => {
      frameworkOptions.value = response || [];
    })
    .catch(() => {
      // 如果接口失败，使用默认选项
      frameworkOptions.value = [
        "TensorFlow",
        "PyTorch",
        "scikit-learn",
        "Keras",
      ];
    });
}

/** 文件上传处理 */
function handleFileChange(file) {
  form.value.algorithmFile = file.raw;
  form.value.algorithmFileList = [file];

  // 上传文件并解析
  if (file.raw) {
    uploadAlgorithmPackage(file.raw)
      .then((response) => {
        // 根据实际返回的数据结构填充表单
        if (response && response.parsed_config) {
          const parsedConfig = response.parsed_config;

          // 填充算法基本信息
          if (parsedConfig.algo_info) {
            const algoInfo = parsedConfig.algo_info;
            form.value.file_id =
              algoInfo.file_id || response.file_id || form.value.file_id;
            form.value.project = algoInfo.project || form.value.project;
            form.value.name = algoInfo.name || form.value.name;
            form.value.scenario = algoInfo.scenario || form.value.scenario;
            form.value.entry_class =
              algoInfo.entry_class || form.value.entry_class;
            form.value.framework = algoInfo.framework || form.value.framework;
            form.value.version = algoInfo.version || form.value.version;
            form.value.python_version =
              algoInfo.python_version || form.value.python_version;
            form.value.description =
              algoInfo.description || form.value.description;
          }

          // 填充测试环境配置
          if (parsedConfig.dev_env && parsedConfig.dev_env.testing_env) {
            const testEnv = parsedConfig.dev_env.testing_env;
            form.value.testApiMethod =
              testEnv.api_method || form.value.testApiMethod;
            form.value.testApiHost = testEnv.api_host || form.value.testApiHost;
            form.value.testApiDataPath =
              testEnv.api_path || form.value.testApiDataPath;
            form.value.testDataRequestClass =
              testEnv.request_class || form.value.testDataRequestClass;
            form.value.testDataResponseClass =
              testEnv.response_class || form.value.testDataResponseClass;
          }

          // 填充生产环境配置
          if (parsedConfig.dev_env && parsedConfig.dev_env.production_env) {
            const prodEnv = parsedConfig.dev_env.production_env;
            form.value.prodApiMethod =
              prodEnv.api_method || form.value.prodApiMethod;
            form.value.prodApiHost = prodEnv.api_host || form.value.prodApiHost;
            form.value.prodApiDataPath =
              prodEnv.api_path || form.value.prodApiDataPath;
            form.value.prodDataRequestClass =
              prodEnv.request_class || form.value.prodDataRequestClass;
            form.value.prodDataResponseClass =
              prodEnv.response_class || form.value.prodDataResponseClass;
          }
        }
        ElMessage.success("文件上传成功，已自动解析算法信息");
      })
      .catch(() => {
        ElMessage.error("文件上传失败");
      });
  }
}

/** 文件上传前检查 */
function beforeUpload(file) {
  const allowedTypes = [
    "application/zip",
    "application/x-tar",
    "application/gzip",
  ];
  const isAllowedType =
    allowedTypes.includes(file.type) ||
    file.name.endsWith(".zip") ||
    file.name.endsWith(".tar") ||
    file.name.endsWith(".tar.gz");

  if (!isAllowedType) {
    ElMessage.error("只能上传压缩文件格式！");
    return false;
  }

  const isLt50M = file.size / 1024 / 1024 < 50;
  if (!isLt50M) {
    ElMessage.error("上传文件大小不能超过 50MB!");
    return false;
  }

  return false; // 阻止自动上传，手动处理
}

/** 移除文件 */
function handleRemoveFile() {
  form.value.algorithmFile = null;
  form.value.algorithmFileList = [];
  form.value.file_id = "";
}

// 组件挂载时初始化
onMounted(() => {
  getFrameworkList();
  getList();
});
</script>

<style scoped>
.form-section {
  margin-bottom: 30px;
  padding: 20px;
  border: 1px solid #ebeef5;
  border-radius: 4px;
}

.section-title {
  font-size: 16px;
  font-weight: 500;
  color: #303133;
  margin: 0 0 20px 0;
  padding-bottom: 10px;
  border-bottom: 1px solid #ebeef5;
}

.env-section {
  margin-top: 20px;
  padding: 15px;
  background-color: #f5f7fa;
  border-radius: 4px;
}

.env-title {
  font-size: 14px;
  font-weight: 500;
  color: #606266;
  margin: 0 0 15px 0;
}

:deep(.el-upload) {
  width: 100%;
}

:deep(.el-upload-dragger) {
  width: 100%;
}
</style>
